package com.partsoft.webs.spring;

import java.io.IOException;
import java.lang.reflect.Field;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.filter.GenericFilterBean;

import com.partsoft.webs.ContextUtils;

@SuppressWarnings("unchecked")
public class ContextResloverFilter extends GenericFilterBean implements
		ServletContextAware, InitializingBean {
	
	protected WebApplicationContext findWebApplicationContext() {
		return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
	}
	
	public void doFilter(ServletRequest servletrequest,
			ServletResponse servletresponse, FilterChain filterchain)
			throws IOException, ServletException {
		ApplicationContext ctx = findWebApplicationContext();
		
		ThreadLocal<ApplicationContext> tlc = null;
		ApplicationContext oldAppCtx = null;
		try {
			if (ctx != null) {
				Field clf = null;
				try {
					clf = ContextUtils.class.getDeclaredField("contextLocal");
				} catch (Exception e) {
					throw new IllegalStateException(e.getMessage(), e);
				}
				boolean oldAcs = clf.isAccessible();
				clf.setAccessible(true);
				tlc = (ThreadLocal<ApplicationContext>) clf.get(null);
				if (tlc != null) {
					oldAppCtx = tlc.get();
					tlc.set(ctx);
				}
				clf.setAccessible(oldAcs);
			}
			filterchain.doFilter(servletrequest, servletresponse);
		} catch (IllegalArgumentException e) {
			throw new ServletException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new ServletException(e.getMessage(), e);
		} finally {
			if (ctx != null && tlc != null) tlc.set(oldAppCtx);
		}
		return;		
	}

	@Override
	public void afterPropertiesSet() throws ServletException {
		super.afterPropertiesSet();
	}

}
